home *** CD-ROM | disk | FTP | other *** search
- /* Read_Res.c - reads a specific resource from a file, and sends
- a formatted text version to the standard out file.
- Retrieves entire data fork if you specify resource type 'data', id 0.
- Shows hex and ascii values in a double-wide format. Note some example
- hAWK programs, eg $Print_MENU_Resource, illustrate analyzing the result
- from Read Resource - format the output, verify resource format. */
-
- /* Copyright © 1991 the Free Software Foundation, Inc.
- * This file is free software; you can redistribute or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 1, or any later version.
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with GAWK; see the file "COPYING hAWK". If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * Written for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
- */
-
- #include "CodeResource.h"
- #include "AppCodeComm.h"
- #include "CodeResHelper.h"
- #include "CodeResFiles.h"
- #include <string.h>
-
- //#if THINK_C >= 5
- //pascal void StringToNum(char *theString,long *theNum);
- //pascal void NumToString(long theNum,char *theString);
- //#endif
-
- #define LoadResID 406
-
- short DoReadRes(void);
- pascal short XferHookPick(short item, DialogPtr dlog);
- Boolean ResForkIsAlreadyOpen(StringPtr fName, short vRefNum);
- Boolean SpecifyResource(long *theTypePtr, short *theIDPtr);
- Boolean BadIDNumber(char *idStr);
- Handle ReadTheResource(StringPtr namePtr, short vref, long theType, short theID);
- Handle ReadDataFork(StringPtr namePtr, short vref);
- Handle FixUpResource(Handle rawH);
- void WriteCharToOutput( char theChar);
- void JumpOnError(void);
-
-
- /* Ask user to pick file, specify resource type and id. Print resource as hex
- and ascii to stdout. Return 1 (show resulting stdout) or -1 (error). */
- short DoReadRes()
- {
- Point where;
- SFReply reply;
- SFTypeList types;
- Handle hText;
- long theType;
- short theID, ret = -1;
-
- /* calculate where to put dialog, so that it'll be centered */
- GetDlogOrigin (getDlgID, &where);
-
- do
- {
- SFGetFile (where, (StringPtr)"", NULL, -1, types, XferHookPick, &reply);
- } while (reply.good && ResForkIsAlreadyOpen((StringPtr)(reply.fName), reply.vRefNum));
- /* If cancelled, forget it */
- if (!reply.good)
- return(-1);
-
- if (!SpecifyResource(&theType, &theID)) return(-1);
-
- /* Read in the resource and write it to stdout */
- if (hText = ReadTheResource ((StringPtr)(reply.fName), reply.vRefNum,theType, theID))
- {
- hText = FixUpResource(hText);
- if (hText)
- {
- if (PutToStdOut(hText))
- ret = 1;
- DisposHandle(hText);
- }
- else
- OKStopAlert("Not quite enough memory to do that, sorry.");
- }
- return(ret);
- }
-
- /* Change name of open button */
- pascal short XferHookPick(short item, DialogPtr dlog)
- {
- short theType;
- Handle theItem;
- Rect theBox;
- char pick[5];
-
- if (item == -1)
- {
- pick[0] = 4;
- pick[1] = 'P';
- pick[2] = 'i';
- pick[3] = 'c';
- pick[4] = 'k';
- GetDItem (dlog, getOpen, &theType, &theItem, &theBox);
- SetCTitle ((ControlHandle)theItem, (StringPtr)pick);
- }
- return (item);
- }
-
- /* Prelim assume that if youve seen one vref youve seen them all.
- Seems that PBGetFCBInfo never sets ioVRefNum, tho perhaps it
- pays attention to it...ioFCBVRefNumis for some reason set
- to the root of the disk. The awkward solution is to determine
- the owning directory ID of the file, and index thru open files,
- checking those that have the same dirID. */
- Boolean ResForkIsAlreadyOpen(StringPtr fName, short vRefNum)
- {
-
- FCBPBRec pb;
- WDPBRec theParms;
- short parentID;
- char fileName[32];
- Boolean resFAlreadyOpen = FALSE;
-
- theParms.ioVRefNum = vRefNum;
- theParms.ioNamePtr = NULL;
- theParms.ioWDIndex = 0;
- theParms.ioWDProcID = 0;
- if (PBGetWDInfo(&theParms, FALSE)) /* trouble of some kind */
- return(TRUE);
- parentID = theParms.ioWDDirID;
- pb.ioCompletion = NULL;
- pb.ioNamePtr = (StringPtr)fileName;
- pb.ioVRefNum = vRefNum;
- pb.ioRefNum = 0;
- pb.ioFCBIndx = 1;
- while (!PBGetFCBInfo(&pb, FALSE))
- {
- if ((short)(pb.ioFCBParID) == parentID)
- {
- if (PEqualStrs((Byte *)fileName, (Byte *)fName))
- {
- resFAlreadyOpen = TRUE;
- break;
- }
- }
- pb.ioVRefNum = vRefNum;
- pb.ioRefNum = 0;
- pb.ioFCBIndx += 1;
- }
-
- if (resFAlreadyOpen)
- {
- OKStopAlert("Please avoid files that are already open.");
- return(TRUE);
- }
- return(FALSE);
- }
-
- /* This should really have popup menus for the resource type and id. */
- Boolean SpecifyResource(long *theTypePtr, short *theIDPtr)
- {
- register DialogPtr dPtr;
- Ptr tempPtr;
- short itemHit, theType, i, numTries;
- Handle theItem;
- Rect theBox;
- char typeStr[10], idStr[10];
- long idNum;
-
- InitCursor ();
-
- if (!GetAndAlignDialog(LoadResID))
- return(FALSE);
- dPtr = GetNewDialog (LoadResID, NULL, (WindowPtr)-1L);
- numTries = 6;
- FrameDialogItem(dPtr,1);
- do{
- --numTries;
- SelIText (dPtr, 5, 0, 502);
-
- /* Give user a chance to change it and see if it's ok */
- ModalDialog (NULL, &itemHit);
-
- if (itemHit == Cancel)
- break;
-
- GetDItem (dPtr, 5, &theType, &theItem, &theBox);
- GetIText (theItem, (StringPtr)typeStr);
- GetDItem (dPtr, 6, &theType, &theItem, &theBox);
- GetIText (theItem, (StringPtr)idStr);
- StringToNum ((StringPtr)idStr, &idNum);
- } while ((BadIDNumber(idStr) || typeStr[0] != 4) && numTries >= 0);
-
-
- /* If cancelled, don't do anything */
- if (itemHit == Cancel || numTries < 0)
- {
- DisposDialog (dPtr);
- return(FALSE);
- }
- tempPtr = (Ptr)theTypePtr;
- for (i = 0; i < 4; ++i)
- *(tempPtr + i) = *(typeStr + i + 1);
-
- *theIDPtr = (short)idNum;
- DisposDialog (dPtr);
- return(TRUE);
- }
-
- /* Return TRUE if id number is BAD.
- Leading white space not allowed.*/
- Boolean BadIDNumber(char *idStr)
- {
- short i, len = idStr[0];
- Boolean minusSeen = FALSE;
-
- if (len < 0 || len > 6) return(TRUE);
- for (i = 1; i <= len; ++i)
- {
- if (idStr[i] == '-')
- {
- if ( i != 1)
- return(TRUE);
- else
- minusSeen = TRUE;
- }
- else if (idStr[i] < '0' || idStr[i] > '9')
- return(TRUE);
- }
- if (!minusSeen && len == 6) return(TRUE);
- return(FALSE);
- }
-
- /* Get the specified resource. Due to overwhelming demand, also read in
- the data fork if wanted - this specified as 'data' id 0. */
- Handle ReadTheResource(StringPtr namePtr, short vref, long theType, short theID)
- {
- short saveVol, refNum;
- Handle rsrcHandle, theHdle = NULL;
- long itemSize;
- short tempfNum;
-
- if (theType == 'data' && !theID) /* data fork requested */
- return(ReadDataFork(namePtr, vref));
- tempfNum = CurResFile();
-
- /* Remember default volume before changing it */
- if (GetVol (NULL, &saveVol))
- saveVol = 0;
-
- /* And set the volume. This must be done because OpenResFile
- looks only in current volume (directory). Actually, it will
- look along the Poor Man's Search Path, but this should do */
-
- SetVol (NULL, vref);
- SetResLoad(FALSE);
- if ((refNum = OpenResFile (namePtr)) != -1)
- {
- SetResLoad(TRUE);
- rsrcHandle = Get1Resource (theType, theID);
-
- if (rsrcHandle)
- {
- itemSize = GetHandleSize(rsrcHandle);
- theHdle = NewHandle(itemSize);
- if (MemError() == noErr)
- BlockMove(*rsrcHandle, *theHdle, itemSize);
- else
- {
- ReleaseResource(rsrcHandle);
- CloseResFile (refNum);
- if (saveVol)
- SetVol (NULL, saveVol);
- UseResFile(tempfNum);
-
- OKStopAlert("Sorry, not enough memory to get the resource.");
- return(NULL);
- }
- ReleaseResource(rsrcHandle);
- }
- else
- OKStopAlert("Sorry, no resource with that type and ID. \
- Try using ResEdit to determine the correct type or number.");
- CloseResFile (refNum);
- }
- else
- {
- SetResLoad(TRUE);
- OKStopAlert("Sorry, couldn't open the resource fork \
- - maybe there isn't one?.");
- }
- /* Restore default volume if any */
- if (saveVol)
- SetVol (NULL, saveVol);
- UseResFile(tempfNum);
-
- return(theHdle);
- }
-
- /* Read in the data fork to a handle. Note if there is
- nothing in the file then NULL is returned rather than an empty
- handle. */
- Handle ReadDataFork(StringPtr namePtr, short vref)
- {
- Handle hText = NULL;
- long count;
- short saveVol, refNum;
- Boolean opened = FALSE;
-
- if (GetVol(NULL, &saveVol))
- saveVol = 0;
- if (FSOpen(namePtr, vref, &refNum))
- goto JumpOut;
- else
- opened = TRUE;
- if (GetEOF(refNum, &count) || count <= 0L)
- goto JumpOut;
- hText = NewHandle(count);
- if (MemError() != noErr)
- {
- MemoryAlert();
- goto JumpOut;
- }
- if (FSRead(refNum, &count, *hText))
- {
- DisposHandle(hText);
- hText = NULL;
- goto JumpOut;
- }
- JumpOut:
- if (opened)
- FSClose(refNum);
- if (saveVol)
- SetVol(NULL, saveVol);
- return(hText);
- }
-
- #include <ctype.h>
- #include <setjmp.h>
-
- /* key code abbreviations - not all used here, but i thot you might like a list... */
- #define ETX '\003' /* enter */
- #define BS '\b' /* backspace */
- #define HT '\t' /* tab */
- #define CR 0x0D /* return */
- #define ESC '\033' /* clear */
- #define FS '\034' /* left arrow */
- #define GS '\035' /* right arrow */
- #define RS '\036' /* up arrow */
- #define US '\037' /* down arrow */
- #define COMMA ',' /* or 0x2C */
- #define BLANK ' ' /* a space */
- #define OPTBL ' ' /* option-space */
- #define COLON ':'
- #define FILLER '.' /* period, for nonascii char*/
-
- #define StdHdleInc 1024L
- static long outSize, privateTrueSize;
- static Handle outH;
-
- /* buffer holding position of long jump */
- jmp_buf LREnvBuf;
-
- Handle FixUpResource(Handle rawH)
- {
- long rawSize = GetHandleSize(rawH),
- startSize = 3*rawSize,
- rawPos = 0L;
- Byte *rawBPtr;
- Ptr rawPtr;
- short byteOff, i, numPads, numDigits;
- char rawChar, theChar, posStr[10];
- Byte rawBChar;
-
- MoveHHi(rawH);
- HLock(rawH);
- rawBPtr = (Byte *)(*rawH);
- rawPtr = *rawH;
- /* set up some convenient static stuff for creating new handle */
- outSize = 0L;
- privateTrueSize = 0L;
- outH = NewHandle(startSize);
- if (MemError() != noErr)
- return(NULL);
- privateTrueSize = startSize;
- if (setjmp(LREnvBuf))
- {
- HUnlock(rawH);
- DisposHandle(rawH);
- DisposHandle(outH);
- return(NULL);
- }
- /* output readable version of resource */
- /* 16 bytes done per line; (8 hex space) 4 times, 16 ascii of same bytes. */
- while (rawPos < rawSize)
- {
- /*WriteCharToOutput(HT); - for extra indent */
- WriteCharToOutput(HT);
- NumToString(rawPos, (StringPtr)posStr);
- numDigits = posStr[0];
- numPads = 5 - numDigits;
- for (i = 0; i < numPads; ++i)
- WriteCharToOutput(BLANK);
- for (i = 1; i <= numDigits; ++i)
- WriteCharToOutput(*(posStr + i));
- WriteCharToOutput(COLON);
- WriteCharToOutput(BLANK);
- byteOff = 16;
- if (rawPos + byteOff >= rawSize)
- byteOff = rawSize - rawPos;
- for (i = 0; i < byteOff; ++i)
- {
- if (i == 4 || i == 8 || i == 12)
- WriteCharToOutput(BLANK);
- rawChar = *(rawPtr + rawPos + i);
- if ((theChar = ((rawChar >>4) & 15)) <= 9)
- theChar += '0';
- else
- theChar += 'A' - 10;
- WriteCharToOutput(theChar);
- if ((theChar = ((rawChar) & 15)) <= 9)
- theChar += '0';
- else
- theChar += 'A' - 10;
- WriteCharToOutput(theChar);
- }
- /* take care of the last short line - pad it out if necessary so that
- text over on the right will still line up with the lines above.
- Revision, after some anguish, pad the last line with zeroes rather
- than blanks, to simplify manipulating the results with a hAWK program. */
- for (; i < 16; ++i)
- {
- if (i == 4 || i == 8 || i == 12)
- WriteCharToOutput(BLANK);
- WriteCharToOutput('0'); /* that's a zero */
- WriteCharToOutput('0');
- }
- WriteCharToOutput(BLANK);
- WriteCharToOutput(BLANK);
- for (i = 0; i < byteOff; ++i)
- {
- rawBChar = *(rawBPtr + rawPos + i);
- if (isprint(rawBChar))
- WriteCharToOutput((char)rawBChar);
- else
- WriteCharToOutput(FILLER);
- }
-
- rawPos += 16L;
- WriteCharToOutput(CR);
- }
-
- /* fix size of handle, dispose raw handle, return */
- SetHandleSize(outH, outSize);
- HUnlock(rawH);
- DisposHandle(rawH);
- return(outH);
- }
-
- void WriteCharToOutput( char theChar)
- {
-
- if (outSize >= privateTrueSize)
- {
- SetHandleSize(outH, privateTrueSize + StdHdleInc);
- if (MemError() != noErr)
- JumpOnError();
- privateTrueSize += StdHdleInc;
- }
- *(*outH + outSize++) = theChar;
- }
-
- void JumpOnError()
- {
-
- longjmp(LREnvBuf, 1); /* return to save point */
- }
-
-